package cn.juque.workflow.service.provider;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.juque.common.annotation.HandlerAppException;
import cn.juque.common.base.BaseOperator;
import cn.juque.common.base.BaseResponseDTO;
import cn.juque.common.base.PageInfo;
import cn.juque.common.constants.MessageEnum;
import cn.juque.common.fastjson.abstracts.AbstractTypeReference;
import cn.juque.common.thread.BaseOperatorThreadLocal;
import cn.juque.common.utils.ValidatorUtil;
import cn.juque.workflow.api.dto.processinfo.ProcessInstanceDeleteDTO;
import cn.juque.workflow.api.dto.taskinfo.*;
import cn.juque.workflow.api.provider.ITaskInfoProvider;
import cn.juque.workflow.bo.*;
import cn.juque.workflow.bo.businesstask.BusinessTaskDetailBO;
import cn.juque.workflow.converter.ProcessTaskConverter;
import cn.juque.workflow.domain.ProcessTaskDO;
import cn.juque.workflow.service.IProcessTaskService;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.task.Task;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * @author juque
 * @version 1.0.0
 * <ul>
 *     <li>TaskInfoProviderImpl</li>
 * </ul>
 * @date 2023-01-30 14:52:53
 **/
@Slf4j
@Service("taskInfoProvider")
@HandlerAppException
public class TaskInfoProviderImpl implements ITaskInfoProvider {

    @Resource
    private ValidatorUtil validatorUtil;

    @Resource
    private IProcessTaskService processTaskService;

    @Resource
    private BaseOperatorThreadLocal baseOperatorThreadLocal;

    /**
     * 查询代办任务
     *
     * @param searchDTO 条件
     * @return list
     */
    @Override
    public BaseResponseDTO<List<TaskInfoListDTO>> listTodo(ListTodoTaskSearchDTO searchDTO) {
        this.validatorUtil.fastValidate(searchDTO);
        PageInfo pageInfo = searchDTO.getPageInfo();
        this.validatorUtil.checkPageInfo(pageInfo);
        ProcessTaskDO processTaskDO = new ProcessTaskDO();
        BeanUtil.copyProperties(searchDTO, processTaskDO);
        List<Task> list = this.processTaskService.list(processTaskDO, pageInfo);
        List<TaskInfoListDTO> result = ProcessTaskConverter.toTaskInfoListDTOList(list);
        return new BaseResponseDTO<>(MessageEnum.OK, result);
    }

    /**
     * 查询已完成的任务
     *
     * @param searchDTO 条件
     * @return list
     */
    @Override
    public BaseResponseDTO<List<TaskInfoListDTO>> listFinish(ListFinishTaskSearchDTO searchDTO) {
        this.validatorUtil.fastValidate(searchDTO);
        PageInfo pageInfo = searchDTO.getPageInfo();
        this.validatorUtil.checkPageInfo(pageInfo);
        ProcessTaskDO processTaskDO = new ProcessTaskDO();
        BeanUtil.copyProperties(searchDTO, processTaskDO);
        List<HistoricTaskInstance> list = this.processTaskService.listFinish(processTaskDO, pageInfo);
        List<TaskInfoListDTO> result = ProcessTaskConverter.toTaskInfoListDtoListByHistory(list);
        return new BaseResponseDTO<>(MessageEnum.OK, result);
    }

    /**
     * 查询可认领的任务
     *
     * @param searchDTO 条件
     * @return list
     */
    @Override
    public BaseResponseDTO<List<TaskInfoListDTO>> listByClaim(ListClaimTaskSearchDTO searchDTO) {
        this.validatorUtil.fastValidate(searchDTO);
        PageInfo pageInfo = searchDTO.getPageInfo();
        this.validatorUtil.checkPageInfo(pageInfo);
        ProcessTaskDO processTaskDO = new ProcessTaskDO();
        BeanUtil.copyProperties(searchDTO, processTaskDO);
        List<Task> list = this.processTaskService.list(processTaskDO, pageInfo);
        List<TaskInfoListDTO> result = ProcessTaskConverter.toTaskInfoListDTOList(list);
        return new BaseResponseDTO<>(MessageEnum.OK, result);
    }

    /**
     * 详情
     *
     * @param searchDTO ProcessInstanceDetailSearchDTO
     * @return ProcessInstanceDetailDTO
     */
    @Override
    public BaseResponseDTO<ProcessInstanceDetailDTO> detail(ProcessInstanceDetailSearchDTO searchDTO) {
        this.validatorUtil.fastValidate(searchDTO);
        BaseOperator baseOperator = searchDTO.getBaseOperator();
        this.baseOperatorThreadLocal.set(baseOperator);
        String processDefinitionKey = searchDTO.getProcessDefinitionKey();
        String businessId = searchDTO.getBusinessId();
        BusinessTaskDetailBO<?> detailBO = this.processTaskService.detail(processDefinitionKey, businessId);
        ProcessInstanceDetailDTO detailDTO = ProcessTaskConverter.toProcessInstanceDetailDTO(detailBO);
        return new BaseResponseDTO<>(MessageEnum.OK, detailDTO);
    }

    /**
     * 详情
     *
     * @param searchDTO ProcessInstanceDetailByTaskSearchDTO
     * @return ProcessInstanceDetailDTO
     */
    @Override
    public BaseResponseDTO<ProcessInstanceDetailDTO> detailByTask(ProcessInstanceDetailByTaskSearchDTO searchDTO) {
        this.validatorUtil.fastValidate(searchDTO);
        BaseOperator baseOperator = searchDTO.getBaseOperator();
        this.baseOperatorThreadLocal.set(baseOperator);
        String processDefinitionKey = searchDTO.getProcessDefinitionKey();
        String taskId = searchDTO.getTaskId();
        BusinessTaskDetailBO<?> detailBO = this.processTaskService.detailByTaskId(processDefinitionKey, taskId);
        ProcessInstanceDetailDTO detailDTO = ProcessTaskConverter.toProcessInstanceDetailDTO(detailBO);
        return new BaseResponseDTO<>(MessageEnum.OK, detailDTO);
    }

    /**
     * 加载bpmn图
     *
     * @param dto 发布ID
     * @return BpmnLoadDTO
     */
    @Override
    public BaseResponseDTO<BpmnLoadDTO> loadBpmnByDeployId(BpmnLoadByDeployIdDTO dto) {
        this.validatorUtil.fastValidate(dto);
        BaseOperator baseOperator = dto.getBaseOperator();
        this.baseOperatorThreadLocal.set(baseOperator);
        BpmnBO bpmnBO = this.processTaskService.loadBpmnByDeployId(dto.getDeployId());
        BpmnLoadDTO bpmnLoadDTO = new BpmnLoadDTO();
        BeanUtil.copyProperties(bpmnBO, bpmnLoadDTO);
        return new BaseResponseDTO<>(MessageEnum.OK, bpmnLoadDTO);
    }

    /**
     * 加载bpmn图
     *
     * @param dto 发布ID
     * @return BpmnLoadDTO
     */
    @Override
    public BaseResponseDTO<BpmnLoadDTO> loadBpmnByInstanceId(BpmnLoadByInstanceIdDTO dto) {
        this.validatorUtil.fastValidate(dto);
        BaseOperator baseOperator = dto.getBaseOperator();
        this.baseOperatorThreadLocal.set(baseOperator);
        BpmnBO bpmnBO = this.processTaskService.loadBpmnByInstanceId(dto.getInstanceId());
        BpmnLoadDTO bpmnLoadDTO = new BpmnLoadDTO();
        BeanUtil.copyProperties(bpmnBO, bpmnLoadDTO);
        return new BaseResponseDTO<>(MessageEnum.OK, bpmnLoadDTO);
    }

    /**
     * 创建流程实例
     *
     * @param createInstanceDTO ProcessCreateInstanceDTO
     * @return Boolean
     */
    @Override
    public BaseResponseDTO<Boolean> createInstance(ProcessCreateInstanceDTO createInstanceDTO) {
        this.validatorUtil.fastValidate(createInstanceDTO);
        BaseOperator baseOperator = createInstanceDTO.getBaseOperator();
        this.baseOperatorThreadLocal.set(baseOperator);
        JSONObject variables = createInstanceDTO.getVariables();
        Map<String, Object> variableMap = null != variables ?
                variables.to(new AbstractTypeReference<Map<String, Object>>() {
                }) : MapUtil.newHashMap();
        InstanceCreateBO createBO = new InstanceCreateBO();
        BeanUtil.copyProperties(createInstanceDTO, createBO);
        createBO.setVariableMap(variableMap);
        this.processTaskService.createInstance(createBO);
        return new BaseResponseDTO<>(MessageEnum.OK, true);
    }

    /**
     * 更新实体类信息
     *
     * @param updateDTO 参数
     * @return Boolean
     */
    @Override
    public BaseResponseDTO<Boolean> updateInstance(ProcessInstanceUpdateDTO updateDTO) {
        this.validatorUtil.fastValidate(updateDTO);
        BaseOperator baseOperator = updateDTO.getBaseOperator();
        this.baseOperatorThreadLocal.set(baseOperator);
        JSONObject variables = updateDTO.getVariables();
        Map<String, Object> variableMap = null != variables ?
                variables.to(new AbstractTypeReference<Map<String, Object>>() {
                }) : MapUtil.newHashMap();
        InstanceUpdateBO instanceUpdateBO = new InstanceUpdateBO();
        BeanUtil.copyProperties(updateDTO, instanceUpdateBO);
        instanceUpdateBO.setVariableMap(variableMap);
        this.processTaskService.updateInstance(instanceUpdateBO);
        return new BaseResponseDTO<>(MessageEnum.OK, true);
    }

    /**
     * 开始流程实例
     *
     * @param startDTO ProcessInstanceStartBO
     * @return Boolean
     */
    @Override
    public BaseResponseDTO<Boolean> startInstance(ProcessInstanceStartDTO startDTO) {
        this.validatorUtil.fastValidate(startDTO);
        BaseOperator baseOperator = startDTO.getBaseOperator();
        this.baseOperatorThreadLocal.set(baseOperator);
        InstanceStartBO instanceStartBO = new InstanceStartBO();
        JSONObject variables = startDTO.getVariables();
        Map<String, Object> variableMap = null != variables ?
                variables.to(new AbstractTypeReference<Map<String, Object>>() {
                }) : MapUtil.newHashMap();
        BeanUtil.copyProperties(startDTO, instanceStartBO);
        instanceStartBO.setVariableMap(variableMap);
        this.processTaskService.startInstance(instanceStartBO);
        return new BaseResponseDTO<>(MessageEnum.OK, true);
    }

    /**
     * 删除流程实例
     *
     * @param deleteDTO ProcessInstanceDeleteDTO
     * @return BaseResponseDTO
     */
    @Override
    public BaseResponseDTO<Boolean> deleteInstance(ProcessInstanceDeleteDTO deleteDTO) {
        this.validatorUtil.fastValidate(deleteDTO);
        BaseOperator baseOperator = deleteDTO.getBaseOperator();
        this.baseOperatorThreadLocal.set(baseOperator);
        String processDefinitionKey = deleteDTO.getProcessDefinitionKey();
        String instanceId = deleteDTO.getInstanceId();
        String reason = deleteDTO.getReason();
        this.processTaskService.deleteInstance(processDefinitionKey, instanceId, reason);
        return null;
    }

    /**
     * 完成当前任务
     *
     * @param paramDTO 参数
     * @return BaseResponseDTO
     */
    @Override
    public BaseResponseDTO<Boolean> taskFinish(TaskFinishParamDTO paramDTO) {
        this.validatorUtil.fastValidate(paramDTO);
        this.baseOperatorThreadLocal.set(paramDTO.getBaseOperator());
        JSONObject variables = paramDTO.getVariables();
        Map<String, Object> variableMap = null != variables ?
                variables.to(new AbstractTypeReference<Map<String, Object>>() {
                }) : MapUtil.newHashMap();
        TaskFinishParamBO paramBO = new TaskFinishParamBO();
        BeanUtil.copyProperties(paramDTO, paramBO);
        paramBO.setVariableMap(variableMap);
        this.processTaskService.taskFinish(paramBO);
        return new BaseResponseDTO<>(MessageEnum.OK, true);
    }

    /**
     * 认领任务
     *
     * @param paramDTO TaskClaimParamDTO
     * @return BaseResponseDTO
     */
    @Override
    public BaseResponseDTO<Boolean> claimTask(TaskClaimParamDTO paramDTO) {
        this.validatorUtil.fastValidate(paramDTO);
        this.baseOperatorThreadLocal.set(paramDTO.getBaseOperator());
        this.processTaskService.claimTask(paramDTO.getTaskId(), paramDTO.getTaskAssignee());
        return new BaseResponseDTO<>(MessageEnum.OK, true);
    }
}
